package com.ys.service.storage.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.ys.entity.storage.*;
import com.ys.enume.finance.TcwOperateFrozenRunningEnum;
import com.ys.enume.storage.TccAllocateDetailEnum;
import com.ys.mapper.storage.TccAllocateDetailMapper;
import com.ys.service.storage.TccStockControlService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ys.dto.AddDto;
import com.ys.entity.flow.YspModel;
import com.ys.entity.sys.TsUserChange;
import com.ys.entity.sys.YsMenu;
import com.ys.entity.sys.YsProcInst;
import com.ys.enume.flow.FlowEnum;
import com.ys.enume.flow.YsProcInstEnum;
import com.ys.mapper.storage.StorageMapper;
import com.ys.mapper.storage.TccAllocateCancelDetailMapper;
import com.ys.mapper.storage.TccAllocateCancelMapper;
import com.ys.service.finance.TcwAccountCountForCompanyService;
import com.ys.service.flow.YspTaskService;
import com.ys.service.storage.TccAllocateCancelService;
import com.ys.util.shiro.ShiroUtils;
import com.ys.vo.Flow;
import com.ys.vo.R;

@Service("tccAllocateCancelService")
public class TccAllocateCancelImpl implements TccAllocateCancelService {

	@Autowired
	private StorageMapper storageMapper;
	@Autowired
	private TccAllocateCancelMapper tccAllocateCancelMapper;
	@Autowired
	private TccAllocateCancelDetailMapper tccAllocateCancelDetailMapper;
	@Autowired
	TcwAccountCountForCompanyService tcwAccountCountForCompanyService;
	@Autowired
	private YspTaskService yspTaskService;

	@Autowired
	private TccAllocateDetailMapper tccAllocateDetailMapper;

    @Autowired
    private TccStockControlService tccStockControlService;
	
	@Override
	@Transactional
	public R add(String bid, String remark, String detailArr, Long menuId) throws Exception {
		
		// 验证订单号
		if (new TccAllocateCancel().setBid(bid).count() > 0) {
			return R.error("该订单号已存在");
		}
		
		// 验证详情
		JSONArray detailJA = JSON.parseArray(detailArr);
		R r = checkDetailJA(detailJA,bid);
		if (r.getCode() == R.Code.FAILED.value) {
			return r;
		}
		
		String loginUserId = ShiroUtils.getUserId();
		TsUserChange tsUserChange = new TsUserChange().setUserId(loginUserId).setStatus(1).queryFirst();
		
		// 添加预约调拨取消单
		TccAllocateCancel entity = null;
		{
			Integer effectStock = FlowEnum.EffectStock.NOT_EFFECT.value;
			Long createChangeId = tsUserChange.getId();
			entity = TccAllocateCancel.tccAllocateCancel(bid, effectStock, createChangeId, remark, 1);
		}
		tccAllocateCancelMapper.insert(entity);
		
		// 添加预约调拨取消单明细
		for (int i = 0; i < detailJA.size(); i++) {
			JSONObject detailJO = detailJA.getJSONObject(i);
			
			String bidAllocateCancel = bid;
			Long allocateDetailId = detailJO.getLong("allocateDetailId");
			Integer num = detailJO.getInteger("canceledNum");
			TccAllocateCancelDetail tccAllocateCancelDetail = TccAllocateCancelDetail.tccAllocateCancelDetail(bidAllocateCancel, allocateDetailId, num, 1);
			tccAllocateCancelDetailMapper.insert(tccAllocateCancelDetail);
		}


		//保存后，修改调拨单取消数量、分配状态
		saveAfterUpdateAllocate(entity,new ArrayList<>());


		/*
		 * 流程初始化
		 */
		YsMenu ysMenu = new YsMenu().setId(menuId).queryFirst();
		if (ysMenu.getFlowModelId().longValue() != 0L) {
			YspModel yspModel = new YspModel().setId(ysMenu.getFlowModelId()).queryFirst();
			String codeModel = yspModel.getCode();
			String createUserId = ShiroUtils.getUserId();
			yspTaskService.init(codeModel, bid, createUserId);
			yspTaskService.setOtherParams(bid,entity.getRemark(),null);
		}
		
		return R.ok(AddDto.gotoEdit("/web/storage/tccAllocateCancel/toFlow?bid=" + entity.getBid()));
	}
	
	@Override
	@Transactional
	public R edit(String bid, String remark, String detailArr, Long menuId) throws Exception {
		
		// 验证是否制单人
		YsProcInst entity = new YsProcInst().setBid(bid).queryFirst();
		if (!entity.getCreateUserId().equals(ShiroUtils.getUserId())) {
			return R.error("非制单人无法修改");
		}
		
		// 验证详情
		JSONArray detailJA = JSON.parseArray(detailArr);
		R r = checkDetailJA(detailJA,bid);
		if (r.getCode() == R.Code.FAILED.value) {
			return r;
		}
		TccAllocateCancel tccAllocateCancel = new TccAllocateCancel().setBid(bid).queryFirst();
		if(remark!=null){
			tccAllocateCancel.setRemark(remark);
			tccAllocateCancelMapper.update(tccAllocateCancel);
			yspTaskService.setOtherParams(bid,tccAllocateCancel.getRemark(),null);
		}

		List<TccAllocateCancelDetail> oldList = new TccAllocateCancelDetail().setBidAllocateCancel(bid).queryList();

		// 删除旧的预约调拨单
		storageMapper.deleteBatchTccAllocateCancelDetailByBid(bid);
		// 添加预约调拨单明细
		for (int i = 0; i < detailJA.size(); i++) {
			JSONObject detailJO = detailJA.getJSONObject(i);
			
			String bidAllocateCancel = bid;
			Long allocateDetailId = detailJO.getLong("allocateDetailId");
			Integer num = detailJO.getInteger("canceledNum");
			TccAllocateCancelDetail tccAllocateCancelDetail = TccAllocateCancelDetail.tccAllocateCancelDetail(bidAllocateCancel, allocateDetailId, num, 1);
			tccAllocateCancelDetailMapper.insert(tccAllocateCancelDetail);
		}
		//保存后，修改调拨单取消数量、分配状态
		saveAfterUpdateAllocate(tccAllocateCancel,oldList);
		
		return R.ok(AddDto.gotoEdit("/web/storage/tccAllocateCancel/toFlow?bid=" + bid));
	}

	//保存后，修改调拨单取消数量、分配状态
	public void saveAfterUpdateAllocate(TccAllocateCancel entity,List<TccAllocateCancelDetail> oldList) throws Exception {
		//如果存在旧数据
		if(oldList!=null && oldList.size()>0){
			//根据旧数据，返还取消数量、分配状态
			backAllocateCancelNum(oldList);
		}
		//扣减 调拨单的 取消数量、分配状态
		addAllocateCancelNum(entity.getBid());
	}


	//扣减 调拨单的 取消数量、分配状态
	public void addAllocateCancelNum(String bid) throws Exception {
		//获取新取消单信息
		List<TccAllocateCancelDetail> newList = new TccAllocateCancelDetail().setBidAllocateCancel(bid).queryList();
		if(newList!=null && newList.size()>0){
			//根据旧数据，返还取消数量、分配状态
			for(TccAllocateCancelDetail newInfo : newList){
				TccAllocateDetail tccAllocateDetail = new TccAllocateDetail().setId(newInfo.getAllocateDetailId()).queryFirst();
				int stateDistribute = TccAllocateDetailEnum.StateDistribute.NO.value;
				int allocateCancelNumByNew = tccAllocateDetail.getAllocateCancelNum() + newInfo.getNum();
				//如果 分配数量+取消数量 == 调拨数量
				if(tccAllocateDetail.getNum() - tccAllocateDetail.getDistributeNum() - allocateCancelNumByNew == 0){
					stateDistribute = TccAllocateDetailEnum.StateDistribute.YES.value;
				}
				tccAllocateDetail.setStateDistribute(stateDistribute);//设置分配状态
				//返还取消数量
				tccAllocateDetail.setAllocateCancelNum(allocateCancelNumByNew);

				//计算未分配数量 = 调拨数量 - 分配数量 - 取消数量
				int mayDistributeNum = tccAllocateDetail.getNum() - tccAllocateDetail.getDistributeNum() - tccAllocateDetail.getAllocateCancelNum();
				tccAllocateDetail.setMayDistributeNum(mayDistributeNum);

				tccAllocateDetailMapper.update(tccAllocateDetail);
			}
		}
	}


	//返还 调拨单的 取消数量、分配状态
	public void backAllocateCancelNum(List<TccAllocateCancelDetail> oldList) throws Exception {
		if(oldList!=null && oldList.size()>0){
			//根据旧数据，返还取消数量、分配状态
			for(TccAllocateCancelDetail oldInfo : oldList){
				TccAllocateDetail tccAllocateDetail = new TccAllocateDetail().setId(oldInfo.getAllocateDetailId()).queryFirst();
				tccAllocateDetail.setStateDistribute(TccAllocateDetailEnum.StateDistribute.NO.value);//返还后必定属于 未分配状态
				int allocateCancelNumByOld = tccAllocateDetail.getAllocateCancelNum();//旧取消数量
				//返还取消数量
				tccAllocateDetail.setAllocateCancelNum(allocateCancelNumByOld-oldInfo.getNum());
				
				//计算未分配数量 = 调拨数量 - 分配数量 - 取消数量
				int mayDistributeNum = tccAllocateDetail.getNum() - tccAllocateDetail.getDistributeNum() - tccAllocateDetail.getAllocateCancelNum();
				tccAllocateDetail.setMayDistributeNum(mayDistributeNum);

				tccAllocateDetailMapper.update(tccAllocateDetail);
			}
		}
	}

	@Override
	@Transactional
	public R deleteTrue(Long id) throws Exception {
		if (id == null) {
			return R.error("ID不能为空");
		}
		TccAllocateCancel entity = new TccAllocateCancel().setId(id).queryFirst();
		if (entity.getEffectStock() == FlowEnum.EffectStock.EFFECTED.value) {
			return R.error("已生效数据无法删除");
		}
		// 验证是否制单人
		String loginUserId = ShiroUtils.getUserId();
		TsUserChange tsUserChange = new TsUserChange().setId(entity.getCreateChangeId()).queryFirst();
		
		if (!tsUserChange.getUserId().equals(loginUserId)) {
			return R.error("非制单人，无法删除");
		}
		
		// 删除主数据
		tccAllocateCancelMapper.deleteTrue(id);

		List<TccAllocateCancelDetail> listDetail = new TccAllocateCancelDetail().setBidAllocateCancel(entity.getBid()).queryList();
		//返还 调拨单的 取消数量、分配状态
		backAllocateCancelNum(listDetail);

		// 删除子数据
		for(TccAllocateCancelDetail detail : listDetail) {
			tccAllocateCancelDetailMapper.deleteTrue(detail.getId());
		}
		
		yspTaskService.flowDelete(entity.getBid(), loginUserId);
		return R.ok();
	}

	@Override
    @Transactional(timeout=120,propagation= Propagation.REQUIRES_NEW)
	public R flowPass(Long id, String loginUserId) throws Exception {
		
		TccAllocateCancel entity = new TccAllocateCancel().setId(id).queryFirst();
		String bid = entity.getBid();
		
		
		try {
			Flow f = yspTaskService.flowPass(bid, loginUserId);
			if (f.getCode() == Flow.Code.FAILED.value) {
				return R.error(f.getMsg());
			} else {
				
				if (f.getState() == Flow.State.FINISH.value) {
					flowFinish(id);
				}
				return R.ok();
			}
		} catch (Exception e) {
			e.printStackTrace();
			return R.error("服务器正在开小差，请联系客服");
		}
	}

	@Override
	public void flowFinish(Long id) throws Exception {
		
		TccAllocateCancel entity = new TccAllocateCancel().setId(id).queryFirst();
		
		YsProcInst ysProcInst = new YsProcInst().setBid(entity.getBid()).queryFirst();
		if (ysProcInst.getStateFlow() != YsProcInstEnum.StateFlow.FINISH.value) {
			return;
		}
		
		entity.setEffectStock(FlowEnum.EffectStock.EFFECTED.value);
		tccAllocateCancelMapper.update(entity);
		
		List<TccAllocateCancelDetail> listDetail = new TccAllocateCancelDetail().setBidAllocateCancel(entity.getBid()).queryList();
		for(TccAllocateCancelDetail detail : listDetail) {
			TccAllocateDetail tccAllocateDetail = new TccAllocateDetail().setId(detail.getAllocateDetailId()).queryFirst();
			BigDecimal amount = tccAllocateDetail.getSinglePrice().multiply(new BigDecimal(detail.getNum()));
			
			// 解冻调入方账户
			tcwAccountCountForCompanyService.thaw(tccAllocateDetail.getVgsbmTo(), amount,
					TcwOperateFrozenRunningEnum.DocumentType.TCC_AllocateCancel.value,
					entity.getId(),
					entity.getBid(),
					null);

			// 变更预约调拨单分配状态
			//storageMapper.updateStateDistributeOfTccAllocateDetail(tccAllocateDetail.getId());
			
		}
	}
	
	/*
	 *  验证详情数据
	 *  1、分配数量不能高于待分配数量
	 *  2、分配数量不能高于库存数量
	 *  3、货位情况不能为空
	 */
	private R checkDetailJA(JSONArray detailJA,String bid) {

		if (detailJA == null || detailJA.size() == 0) {
			return R.error("详情数据不能为空");
		} else {

			List<TccAllocateCancelDetail> oldList = new TccAllocateCancelDetail().setBidAllocateCancel(bid).queryList();


			for (int i = 0; i < detailJA.size(); i++) {
				JSONObject detailJO = detailJA.getJSONObject(i);
				Long allocateDetailId = detailJO.getLong("allocateDetailId");
				if (allocateDetailId == null) {
					return R.error("预约调拨详情ID不能为空");
				}
				TccAllocateDetail tccAllocateDetail = new TccAllocateDetail().setId(allocateDetailId).queryFirst();

				//获取单据本身旧的已取消数量
				int allocateCancelNumByThis = 0;
				if(oldList!=null && oldList.size()>0){
					for(TccAllocateCancelDetail detail : oldList){
						long allocateDetailIdByOld = detail.getAllocateDetailId();
						if(allocateDetailIdByOld == tccAllocateDetail.getId()){
							allocateCancelNumByThis = allocateCancelNumByThis + detail.getNum();
						}

					}
				}

				// 待分配数量 = 调拨数量 - 已分配数量 - 已取消数量 + 单据本身旧的已取消数量
				Integer unDistributeNum = tccAllocateDetail.getNum()
						- tccAllocateDetail.getDistributeNum()
						- tccAllocateDetail.getAllocateCancelNum()
						+ allocateCancelNumByThis;

				Integer canceledNum = detailJO.getInteger("canceledNum");
				if (canceledNum == null || canceledNum <= 0) {
					return R.error("第"+(i+1)+"条数据，取消数量不能为空且必须大于0");
				} else if (canceledNum > unDistributeNum) {
					return R.error("第"+(i+1)+"条数据，取消数量超过待分配数量");
				}
			}
			
			return R.ok();
		}
	}


	//获取列表数据
	@Override
	@Transactional
	public Map<String,Object> getExtraParam( String bid) throws Exception{
		Map<String,Object> extraParam = new TccAllocateCancel()

				.addLeftJoin("YS_ProcInst P ON P.Bid = A.Bid ")
				.addField("FORMAT(P.UpdateTime, 'yyyy-MM-dd HH:mm:ss') AS auditingTime")//审核时间
				.setBid(bid)
				.queryFirstMap();
		return extraParam;
	}


	//获取子列表数据
	@Override
	@Transactional
	public List<Map<String, Object>> getItemList(String bid) throws Exception{
		// 子列表配置信息
		List<Map<String, Object>> sonlist = new TccAllocateCancelDetail()
				.setBidAllocateCancel(bid)
				.addLeftJoin("TCC_AllocateDetail B on B.Id = A.AllocateDetailId")
				.addField("B.ProductCode productCode")
				.addField("B.ProductName productName")
				.addField("B.VgsbmFrom vgsbmFrom")
				.addField("B.VgsjcFrom vgsjcFrom")
				.addField("B.VgsbmTo vgsbmTo")
				.addField("B.VgsjcTo vgsjcTo")
				.addField("B.Num allocateNum")
				.addLeftJoin("TCC_Allocate C on C.Bid = B.BidAllocate")
				.addField("C.Bid bidAllocate")
				.addField("C.Type allocateType")
				.addField("B.DistributeNum distributeNum")
				.addField("B.AllocateCancelNum distributedNum")
                .addField("A.Num canceledNum")

				.queryMap();
		return sonlist;
	}



}
